﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using Universe.MediaProbe.External;
using Universe.MediaProbe.Utils;

namespace Universe.MediaProbe
{
    // ffmpeg 
    // -ss 00:00:05.74            start frame
    // -i "Vintage Columbia 1959.mp4" 
    // -q:v 2                     jpg only, 2-max 31-min
    // -r 10                      framerate
    // -vframes 4                 number pf frames
    // -s 400x600                 output size
    // mytemp\image-%%6d.jpg      output file names pattern
    public class ScreenGrabImpl
    {

        static string GetTempFolder()
        {
            string folder = Path.Combine(
                ExternalSource.GetTempFolderSmarty(),
                "screen-" + Guid.NewGuid().ToString("N")
                );

            try
            {
                Directory.CreateDirectory(folder);
            }
            catch
            {
            }

            if (!Directory.Exists(folder))
                throw new InvalidOperationException("Access to temp folder denied");

            return folder;
        }

        public static IEnumerable<string> Grab(
            string inputFile,
            decimal start, int frames, decimal frameRate,
            ScreenGrabber.OutputEncoder encoder,
            int jpegQuality,
            int optionalWidth,
            int optionalHeight,
            out string folder)
        {
            StringBuilder ab = new StringBuilder();

            ab.Append(" -ss ").Append(ToEnTime(start));
            ab.Append(" -i \"").Append(inputFile).Append('"');

            if (frames > 1)
                ab
                    .Append(" -r ").Append(ToEnDecimal(frameRate));
                    

            ab.Append(" -vframes ").Append(frames.ToString("0"));

            if (optionalHeight > 0 && optionalWidth > 0)
                ab.Append(" -s ").Append(optionalWidth.ToString("0")).Append("x").Append(optionalHeight.ToString("0"));

            if (encoder == ScreenGrabber.OutputEncoder.Jpeg)
                ab.Append(" -q:v ").Append(jpegQuality.ToString("0"));

            folder = GetTempFolder();
            var outExtention = encoder.ToString().ToLower().Replace("jpeg", "jpg");
            ab
                .Append(" \"")
                .Append(Path.Combine(folder, "frame-%6d." + outExtention))
                .Append('"');

            // Trace.WriteLine("Screenshot arguments: " + ab);
            

            //  -q:v 1 -vframes 1 -ss 00:00:05.000 -s 1000x666 "/root/.tmp/ffmpeg working folder/screen-fbadecb7c151495591f6229663d38e78/frame-%6d.jpeg" -i "/root/.tmp/Test Video Source/Universe.mp4"
            string args = ab.ToString();

            string exeConvert = ExternalSource.GetFFMpegFile();
            
            // TODO: Cache it
            if (
                CrossInfo.ThePlatform != CrossInfo.Platform.Windows
                && !ProbeReportBuilder.GetImplementationInfo(ProbeReportBuilder.Implementation.FF).IsPresent)
                exeConvert = "avconv";

            ProcessStartInfo si = new ProcessStartInfo(exeConvert, args)
            {
                CreateNoWindow = true,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                // StandardErrorEncoding = Encoding.UTF8,
                StandardOutputEncoding = Encoding.UTF8,
                WindowStyle = ProcessWindowStyle.Hidden,
                UseShellExecute = false,
            };

            if (true || CrossInfo.ThePlatform != CrossInfo.Platform.Windows)
            {
                Trace.WriteLine("Try screenshots: " + Environment.NewLine + "   " + si.FileName + " " + si.Arguments);
            }

            /*
                        Trace.WriteLine("Folder: " + folder);
                        Trace.WriteLine("   Exe: " + exeConvert);
                        Trace.WriteLine("  Args: " + args);
            */

            Process p = new Process()
            {
                StartInfo = si,
            };

            // error is written to output xml
            ManualResetEvent outputDone = new ManualResetEvent(false);
            string outputString = null;
            Exception outputException = null;


            using (p)
            {
                p.Start();
                outputString = p.StandardOutput.ReadToEnd();
                p.WaitForExit();

                // if (CrossInfo.ThePlatform != CrossInfo.Platform.Windows) Trace.WriteLine("Screenshot output: " + Environment.NewLine + outputString);

            }

            if (outputString == null)
            {
                const string message = "ffmpeg's any output is expected";
                if (outputException == null)
                    throw new InvalidOperationException(message);
                else
                    throw new InvalidOperationException(message, outputException);
            }

            UTF8Encoding enc = new UTF8Encoding(false);
            byte[] response = enc.GetBytes(outputString);

            var ret = Directory.GetFiles(folder);
            foreach (var s in ret)
            {
                SmartyTemp.KillOnRestart(s);
                // Trace.WriteLine(" Frame: " + s);
            }

            SmartyTemp.KillOnRestart(folder);
            Array.Sort(ret, StringComparer.CurrentCultureIgnoreCase);
            return ret;
        }


        static readonly CultureInfo enUS = new CultureInfo("en-US");
        
        static string ToEnDecimal(decimal arg)
        {
            return arg.ToString("#0.00000", enUS);
        }

        static string ToEnTime(decimal time)
        {
            var t = TimeSpan.FromSeconds((double) time);
            return string.Format(enUS, "{0:00}:{1:00}:{2:00}.{3:000}",
                t.Days * 24 + t.Hours, t.Minutes, t.Seconds, t.Milliseconds
                );
        }

    }
}
